{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "xfcSMZEIFA_l"
   },
   "source": [
    "# ML with TensorFlow Extended (TFX) -- Part 1\n",
    "The puprpose of this tutorial is to show how to do end-to-end ML with TFX libraries on Google Cloud Platform. This tutorial covers:\n",
    "1. Data analysis and schema generation with **TF Data Validation**.\n",
    "2. Data preprocessing with **TF Transform**.\n",
    "3. Model training with **TF Estimator**.\n",
    "4. Model evaluation with **TF Model Analysis**.\n",
    "\n",
    "This notebook has been tested in Jupyter on the Deep Learning VM.\n",
    "\n",
    "## 0. Setup Python and Cloud environment\n",
    "\n",
    "Install the libraries we need and set up variables to reference our project and bucket."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "JkkjO6RyH5UP"
   },
   "outputs": [],
   "source": [
    "%pip install -q --upgrade grpcio_tools tensorflow_data_validation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/jupyter/.local/lib/python3.5/site-packages/apache_beam/__init__.py:84: UserWarning: Running the Apache Beam SDK on Python 3 is not yet fully supported. You may encounter buggy behavior or missing features.\n",
      "  'Running the Apache Beam SDK on Python 3 is not yet fully supported. '\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tornado version: 6.0.2\n",
      "Python version: 3.5.3\n",
      "TF version: 1.13.1\n",
      "TFT version: 0.13.0\n",
      "TFDV version: 0.13.1\n",
      "Apache Beam version: 2.11.0\n"
     ]
    }
   ],
   "source": [
    "import apache_beam as beam\n",
    "import platform\n",
    "import tensorflow as tf\n",
    "import tensorflow_data_validation as tfdv\n",
    "import tensorflow_transform as tft\n",
    "import tornado\n",
    "\n",
    "print('tornado version: {}'.format(tornado.version))\n",
    "print('Python version: {}'.format(platform.python_version()))\n",
    "print('TF version: {}'.format(tf.__version__))\n",
    "print('TFT version: {}'.format(tft.__version__))\n",
    "print('TFDV version: {}'.format(tfdv.__version__))\n",
    "print('Apache Beam version: {}'.format(beam.__version__))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "PROJECT = 'cloud-training-demos'    # Replace with your PROJECT\n",
    "BUCKET = 'cloud-training-demos-ml'  # Replace with your BUCKET\n",
    "REGION = 'us-central1'              # Choose an available region for Cloud MLE\n",
    "\n",
    "import os\n",
    "\n",
    "os.environ['PROJECT'] = PROJECT\n",
    "os.environ['BUCKET'] = BUCKET\n",
    "os.environ['REGION'] = REGION"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Updated property [core/project].\n",
      "Updated property [compute/region].\n",
      "Updated property [ml_engine/local_python].\n"
     ]
    }
   ],
   "source": [
    "%%bash\n",
    "gcloud config set project $PROJECT\n",
    "gcloud config set compute/region $REGION\n",
    "\n",
    "## ensure we predict locally with our current Python environment\n",
    "gcloud config set ml_engine/local_python `which python`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img valign=\"middle\" src=\"images/tfx.jpeg\">"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "l9u699PmHJXU"
   },
   "source": [
    "### Flights dataset\n",
    "\n",
    "We'll use the flights dataset from the book [Data Science on Google Cloud Platform](http://shop.oreilly.com/product/0636920057628.do)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "DATA_BUCKET = \"gs://cloud-training-demos/flights/chapter8/output/\"\n",
    "TRAIN_DATA_PATTERN = DATA_BUCKET + \"train*\"\n",
    "EVAL_DATA_PATTERN = DATA_BUCKET + \"test*\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 51
    },
    "colab_type": "code",
    "id": "ksuSTsysHfZV",
    "outputId": "87adfbf0-be77-4d81-9162-5a2f9feffd90"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "  19791059  2018-11-30T01:26:30Z  gs://cloud-training-demos/flights/chapter8/output/trainFlights-00000-of-00007.csv\n",
      " 113651981  2018-11-30T01:26:33Z  gs://cloud-training-demos/flights/chapter8/output/trainFlights-00001-of-00007.csv\n",
      " 141696199  2018-11-30T01:26:34Z  gs://cloud-training-demos/flights/chapter8/output/trainFlights-00002-of-00007.csv\n",
      "   1861214  2018-11-30T01:26:29Z  gs://cloud-training-demos/flights/chapter8/output/trainFlights-00003-of-00007.csv\n",
      "   6713759  2018-11-30T01:26:29Z  gs://cloud-training-demos/flights/chapter8/output/trainFlights-00004-of-00007.csv\n",
      "   1900597  2018-11-30T01:26:29Z  gs://cloud-training-demos/flights/chapter8/output/trainFlights-00005-of-00007.csv\n",
      " 151664685  2018-11-30T01:26:35Z  gs://cloud-training-demos/flights/chapter8/output/trainFlights-00006-of-00007.csv\n",
      "TOTAL: 7 objects, 437279494 bytes (417.02 MiB)\n",
      "   2686954  2018-11-30T01:26:29Z  gs://cloud-training-demos/flights/chapter8/output/testFlights-00000-of-00007.csv\n",
      "    749937  2018-11-30T01:26:29Z  gs://cloud-training-demos/flights/chapter8/output/testFlights-00001-of-00007.csv\n",
      "    758408  2018-11-30T01:26:29Z  gs://cloud-training-demos/flights/chapter8/output/testFlights-00002-of-00007.csv\n",
      "  60710391  2018-11-30T01:26:31Z  gs://cloud-training-demos/flights/chapter8/output/testFlights-00003-of-00007.csv\n",
      "   7914629  2018-11-30T01:26:29Z  gs://cloud-training-demos/flights/chapter8/output/testFlights-00004-of-00007.csv\n",
      "  45451451  2018-11-30T01:26:31Z  gs://cloud-training-demos/flights/chapter8/output/testFlights-00005-of-00007.csv\n",
      "  56736391  2018-11-30T01:26:31Z  gs://cloud-training-demos/flights/chapter8/output/testFlights-00006-of-00007.csv\n",
      "TOTAL: 7 objects, 175008161 bytes (166.9 MiB)\n",
      "0.0,14.0,13.0,319.0,25.863039,27.0,WN,32.84722222,-96.85166667,31.94250000,-102.20194444,DAL,MAF\n"
     ]
    }
   ],
   "source": [
    "!gcloud storage ls --long $TRAIN_DATA_PATTERN\n",    "!gcloud storage ls --long $EVAL_DATA_PATTERN\n",    "!gcloud storage cat $DATA_BUCKET'trainFlights-00000-of-00007.csv' | head -1"   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "QzCKD9Q8Gzry"
   },
   "source": [
    "## 1. Data Analysis\n",
    "For data analysis, visualization, and schema generation, we use [TensorFlow Data Validation](https://www.tensorflow.org/tfx/guide/tfdv) to perform the following:\n",
    "1. **Analyze** the training data and produce **statistics**.\n",
    "2. Generate data **schema** from the produced statistics.\n",
    "3. **Configure** the schema.\n",
    "4. **Validate** the evaluation data against the schema.\n",
    "5. **Save** the schema for later use."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 34
    },
    "colab_type": "code",
    "id": "mi9OtQTVG0Ai",
    "outputId": "8aa85a66-c278-4d11-b7cf-4abd7bd7f35f"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "TFDV version: 0.13.1\n"
     ]
    }
   ],
   "source": [
    "import tensorflow_data_validation as tfdv\n",
    "print('TFDV version: {}'.format(tfdv.__version__))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "_S9QVPv3JYqM"
   },
   "source": [
    "### 1.1 Compute and visualise statistics"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "TETRPJXGJdWC"
   },
   "outputs": [],
   "source": [
    "CSV_COLUMNS = ('ontime,dep_delay,taxiout,distance,avg_dep_delay,avg_arr_delay' + \n",
    "               ',carrier,dep_lat,dep_lon,arr_lat,arr_lon,origin,dest').split(',')\n",
    "TARGET_FEATURE_NAME = 'ontime'\n",
    "DEFAULTS     = [[0.0],[0.0],[0.0],[0.0],[0.0],[0.0],\\\n",
    "                ['na'],[0.0],[0.0],[0.0],[0.0],['na'],['na']]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "WARNING:root:Couldn't find python-snappy so the implementation of _TFRecordUtil._masked_crc32c is not as fast as it could be.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "WARNING:tensorflow:From /home/jupyter/.local/lib/python3.5/site-packages/tensorflow_data_validation/utils/stats_gen_lib.py:328: tf_record_iterator (from tensorflow.python.lib.io.tf_record) is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "Use eager execution and: \n",
      "`tf.data.TFRecordDataset(path)`\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "WARNING:tensorflow:From /home/jupyter/.local/lib/python3.5/site-packages/tensorflow_data_validation/utils/stats_gen_lib.py:328: tf_record_iterator (from tensorflow.python.lib.io.tf_record) is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "Use eager execution and: \n",
      "`tf.data.TFRecordDataset(path)`\n"
     ]
    }
   ],
   "source": [
    "# This is a convenience function for CSV. We can write a Beam pipeline for other formats.\n",
    "# https://www.tensorflow.org/tfx/data_validation/api_docs/python/tfdv/generate_statistics_from_csv\n",
    "train_stats = tfdv.generate_statistics_from_csv(\n",
    "    data_location=TRAIN_DATA_PATTERN, \n",
    "    column_names=CSV_COLUMNS,\n",
    "    stats_options=tfdv.StatsOptions(sample_rate=0.1)\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 545
    },
    "colab_type": "code",
    "id": "baquhTcwJncI",
    "outputId": "7fd3e7ee-e25e-4930-afda-4f3fb6dc9271"
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<iframe id='facets-iframe' width=\"100%\" height=\"500px\"></iframe>\n",
       "        <script>\n",
       "        facets_iframe = document.getElementById('facets-iframe');\n",
       "        facets_html = '<link rel=\"import\" href=\"https://raw.githubusercontent.com/PAIR-code/facets/master/facets-dist/facets-jupyter.html\"><facets-overview proto-input=\"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\"></facets-overview>';\n",
       "        facets_iframe.contentWindow.document.write(facets_html);\n",
       "         facets_iframe.id = \"\";\n",
       "         setTimeout(() => {\n",
       "           facets_iframe.setAttribute('height', facets_iframe.contentWindow.document.body.offsetHeight + 'px')\n",
       "         }, 1500)\n",
       "         </script>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "tfdv.visualize_statistics(train_stats)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "YBWsZpDGJrBw"
   },
   "source": [
    "### 1.2 Infer Schema"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 904
    },
    "colab_type": "code",
    "id": "TLjiTL0VJyWl",
    "outputId": "3f2ff4c8-3ffe-4954-8236-529e83606e20"
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Type</th>\n",
       "      <th>Presence</th>\n",
       "      <th>Valency</th>\n",
       "      <th>Domain</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Feature name</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>'distance'</th>\n",
       "      <td>FLOAT</td>\n",
       "      <td>required</td>\n",
       "      <td></td>\n",
       "      <td>-</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>'arr_lon'</th>\n",
       "      <td>FLOAT</td>\n",
       "      <td>required</td>\n",
       "      <td></td>\n",
       "      <td>-</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>'origin'</th>\n",
       "      <td>BYTES</td>\n",
       "      <td>required</td>\n",
       "      <td></td>\n",
       "      <td>-</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>'dep_lon'</th>\n",
       "      <td>FLOAT</td>\n",
       "      <td>required</td>\n",
       "      <td></td>\n",
       "      <td>-</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>'avg_arr_delay'</th>\n",
       "      <td>FLOAT</td>\n",
       "      <td>required</td>\n",
       "      <td></td>\n",
       "      <td>-</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>'ontime'</th>\n",
       "      <td>FLOAT</td>\n",
       "      <td>required</td>\n",
       "      <td></td>\n",
       "      <td>-</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>'taxiout'</th>\n",
       "      <td>FLOAT</td>\n",
       "      <td>required</td>\n",
       "      <td></td>\n",
       "      <td>-</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>'dest'</th>\n",
       "      <td>BYTES</td>\n",
       "      <td>required</td>\n",
       "      <td></td>\n",
       "      <td>-</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>'arr_lat'</th>\n",
       "      <td>FLOAT</td>\n",
       "      <td>required</td>\n",
       "      <td></td>\n",
       "      <td>-</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>'dep_delay'</th>\n",
       "      <td>FLOAT</td>\n",
       "      <td>required</td>\n",
       "      <td></td>\n",
       "      <td>-</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>'avg_dep_delay'</th>\n",
       "      <td>FLOAT</td>\n",
       "      <td>required</td>\n",
       "      <td></td>\n",
       "      <td>-</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>'carrier'</th>\n",
       "      <td>STRING</td>\n",
       "      <td>required</td>\n",
       "      <td></td>\n",
       "      <td>'carrier'</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>'dep_lat'</th>\n",
       "      <td>FLOAT</td>\n",
       "      <td>required</td>\n",
       "      <td></td>\n",
       "      <td>-</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                   Type  Presence Valency     Domain\n",
       "Feature name                                        \n",
       "'distance'        FLOAT  required                  -\n",
       "'arr_lon'         FLOAT  required                  -\n",
       "'origin'          BYTES  required                  -\n",
       "'dep_lon'         FLOAT  required                  -\n",
       "'avg_arr_delay'   FLOAT  required                  -\n",
       "'ontime'          FLOAT  required                  -\n",
       "'taxiout'         FLOAT  required                  -\n",
       "'dest'            BYTES  required                  -\n",
       "'arr_lat'         FLOAT  required                  -\n",
       "'dep_delay'       FLOAT  required                  -\n",
       "'avg_dep_delay'   FLOAT  required                  -\n",
       "'carrier'        STRING  required          'carrier'\n",
       "'dep_lat'         FLOAT  required                  -"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Values</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Domain</th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>'carrier'</th>\n",
       "      <td>'AA', 'AS', 'B6', 'DL', 'EV', 'F9', 'HA', 'MQ', 'NK', 'OO', 'UA', 'US', 'VX', 'WN'</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                                                                                       Values\n",
       "Domain                                                                                       \n",
       "'carrier'  'AA', 'AS', 'B6', 'DL', 'EV', 'F9', 'HA', 'MQ', 'NK', 'OO', 'UA', 'US', 'VX', 'WN'"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "schema = tfdv.infer_schema(statistics=train_stats)\n",
    "tfdv.display_schema(schema=schema)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "E8eJ8S-6Kdrt"
   },
   "source": [
    "### 1.3 Configure Schema\n",
    "\n",
    "Specify some tolerance for values."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "Gbdf-zRXKiAp"
   },
   "outputs": [],
   "source": [
    "# Relax the minimum fraction of values that must come from the domain for feature occupation.\n",
    "carrier = tfdv.get_feature(schema, 'carrier')\n",
    "carrier.distribution_constraints.min_domain_mass = 0.9\n",
    "\n",
    "# All features are by default in both TRAINING and SERVING environments.\n",
    "#schema.default_environment.append('TRAINING')\n",
    "#schema.default_environment.append('EVALUATION')\n",
    "#schema.default_environment.append('SERVING')\n",
    "\n",
    "# Specify that weight and class feature is not in SERVING environment.\n",
    "#tfdv.get_feature(schema, TARGET_FEATURE_NAME).not_in_environment.append('SERVING')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "DUtiulVrNZLU"
   },
   "source": [
    "### 1.4 Validate evaluation data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 111
    },
    "colab_type": "code",
    "id": "95Lit8o4NYuf",
    "outputId": "22f24a8d-4dca-4452-c9bf-5a326d88e659"
   },
   "outputs": [],
   "source": [
    "eval_stats = tfdv.generate_statistics_from_csv(EVAL_DATA_PATTERN, column_names=CSV_COLUMNS)\n",
    "eval_anomalies = tfdv.validate_statistics(eval_stats, schema) #, environment='EVALUATION')\n",
    "tfdv.display_anomalies(eval_anomalies)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "TEm6B1qnOzTL"
   },
   "source": [
    "### 1.5 Freeze the schema"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "RAW_SCHEMA_LOCATION = 'raw_schema.pbtxt'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "colab": {},
    "colab_type": "code",
    "id": "iz-WzwYvOzhG"
   },
   "outputs": [],
   "source": [
    "from tensorflow.python.lib.io import file_io\n",
    "from google.protobuf import text_format\n",
    "\n",
    "tfdv.write_schema_text(schema, RAW_SCHEMA_LOCATION)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "feature {\n",
      "  name: \"distance\"\n",
      "  type: FLOAT\n",
      "  presence {\n",
      "    min_fraction: 1.0\n",
      "    min_count: 1\n",
      "  }\n",
      "  shape {\n",
      "    dim {\n",
      "      size: 1\n",
      "    }\n",
      "  }\n",
      "}\n",
      "feature {\n",
      "  name: \"arr_lon\"\n",
      "  type: FLOAT\n",
      "  presence {\n",
      "    min_fraction: 1.0\n",
      "    min_count: 1\n",
      "  }\n",
      "  shape {\n",
      "    dim {\n",
      "      size: 1\n",
      "    }\n",
      "  }\n",
      "}\n",
      "feature {\n",
      "  name: \"origin\"\n",
      "  type: BYTES\n",
      "  presence {\n",
      "    min_fraction: 1.0\n",
      "    min_count: 1\n",
      "  }\n",
      "  shape {\n",
      "    dim {\n",
      "      size: 1\n",
      "    }\n",
      "  }\n",
      "}\n",
      "feature {\n",
      "  name: \"dep_lon\"\n",
      "  type: FLOAT\n",
      "  presence {\n",
      "    min_fraction: 1.0\n",
      "    min_count: 1\n",
      "  }\n",
      "  shape {\n",
      "    dim {\n",
      "      size: 1\n",
      "    }\n",
      "  }\n",
      "}\n",
      "feature {\n",
      "  name: \"avg_arr_delay\"\n",
      "  type: FLOAT\n",
      "  presence {\n",
      "    min_fraction: 1.0\n",
      "    min_count: 1\n",
      "  }\n",
      "  shape {\n",
      "    dim {\n",
      "      size: 1\n",
      "    }\n",
      "  }\n",
      "}\n",
      "feature {\n",
      "  name: \"ontime\"\n",
      "  type: FLOAT\n",
      "  presence {\n",
      "    min_fraction: 1.0\n",
      "    min_count: 1\n",
      "  }\n",
      "  shape {\n",
      "    dim {\n",
      "      size: 1\n",
      "    }\n",
      "  }\n",
      "}\n",
      "feature {\n",
      "  name: \"taxiout\"\n",
      "  type: FLOAT\n",
      "  presence {\n",
      "    min_fraction: 1.0\n",
      "    min_count: 1\n",
      "  }\n",
      "  shape {\n",
      "    dim {\n",
      "      size: 1\n",
      "    }\n",
      "  }\n",
      "}\n",
      "feature {\n",
      "  name: \"dest\"\n",
      "  type: BYTES\n",
      "  presence {\n",
      "    min_fraction: 1.0\n",
      "    min_count: 1\n",
      "  }\n",
      "  shape {\n",
      "    dim {\n",
      "      size: 1\n",
      "    }\n",
      "  }\n",
      "}\n",
      "feature {\n",
      "  name: \"arr_lat\"\n",
      "  type: FLOAT\n",
      "  presence {\n",
      "    min_fraction: 1.0\n",
      "    min_count: 1\n",
      "  }\n",
      "  shape {\n",
      "    dim {\n",
      "      size: 1\n",
      "    }\n",
      "  }\n",
      "}\n",
      "feature {\n",
      "  name: \"dep_delay\"\n",
      "  type: FLOAT\n",
      "  presence {\n",
      "    min_fraction: 1.0\n",
      "    min_count: 1\n",
      "  }\n",
      "  shape {\n",
      "    dim {\n",
      "      size: 1\n",
      "    }\n",
      "  }\n",
      "}\n",
      "feature {\n",
      "  name: \"avg_dep_delay\"\n",
      "  type: FLOAT\n",
      "  presence {\n",
      "    min_fraction: 1.0\n",
      "    min_count: 1\n",
      "  }\n",
      "  shape {\n",
      "    dim {\n",
      "      size: 1\n",
      "    }\n",
      "  }\n",
      "}\n",
      "feature {\n",
      "  name: \"carrier\"\n",
      "  type: BYTES\n",
      "  domain: \"carrier\"\n",
      "  presence {\n",
      "    min_fraction: 1.0\n",
      "    min_count: 1\n",
      "  }\n",
      "  distribution_constraints {\n",
      "    min_domain_mass: 0.9\n",
      "  }\n",
      "  shape {\n",
      "    dim {\n",
      "      size: 1\n",
      "    }\n",
      "  }\n",
      "}\n",
      "feature {\n",
      "  name: \"dep_lat\"\n",
      "  type: FLOAT\n",
      "  presence {\n",
      "    min_fraction: 1.0\n",
      "    min_count: 1\n",
      "  }\n",
      "  shape {\n",
      "    dim {\n",
      "      size: 1\n",
      "    }\n",
      "  }\n",
      "}\n",
      "string_domain {\n",
      "  name: \"carrier\"\n",
      "  value: \"AA\"\n",
      "  value: \"AS\"\n",
      "  value: \"B6\"\n",
      "  value: \"DL\"\n",
      "  value: \"EV\"\n",
      "  value: \"F9\"\n",
      "  value: \"HA\"\n",
      "  value: \"MQ\"\n",
      "  value: \"NK\"\n",
      "  value: \"OO\"\n",
      "  value: \"UA\"\n",
      "  value: \"US\"\n",
      "  value: \"VX\"\n",
      "  value: \"WN\"\n",
      "}\n"
     ]
    }
   ],
   "source": [
    "!cat {RAW_SCHEMA_LOCATION}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "Gsi_Hsh89Cl7"
   },
   "source": [
    "## License"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "colab_type": "text",
    "id": "0fOWx1yI9Dyn"
   },
   "source": [
    "Copyright 2019 Google LLC\n",
    "\n",
    "Licensed under the Apache License, Version 2.0 (the \"License\");\n",
    "you may not use this file except in compliance with the License.\n",
    "You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.\n",
    "\n",
    "Unless required by applicable law or agreed to in writing, software\n",
    "distributed under the License is distributed on an \"AS IS\" BASIS,\n",
    "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
    "See the License for the specific language governing permissions and\n",
    "limitations under the License.\n",
    "\n",
    "---\n",
    "**Disclaimer**: This is not an official Google product. The sample code provided for an educational purpose.\n",
    "\n",
    "---"
   ]
  }
 ],
 "metadata": {
  "colab": {
   "collapsed_sections": [],
   "name": "02-tfx_end_to_end",
   "provenance": [],
   "version": "0.3.2"
  },
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
